((global, factory) => {
    typeof exports === "object" && typeof module !== "undefined"
        ? (module.exports = factory(global))
        : typeof define === "function" && define.amd
            ? define(() => factory(global))
            : ((global =
                typeof globalThis !== "undefined" ? globalThis : global || self),
                (global.mfoSocketControl = factory(global)));
})(window, (global) => {
    class SocketControl {
        constructor(options) {
            if (options) {
                this.options = options || {};
            }
            this.SOCKETAPIURL = this.options.url;
            this.DELAY = this.options.delay || 15000;
            this.RELOAD = this.options.reload || false;
            this.RELOADTOTAL = this.options.reloadTotal || 3;
            this.createSocket().catch(err => console.error(err));
            return this;
        }
        options = {
            url: undefined,
            delay: 15000,
            reload: false,
            reloadTotal: 3
        };
        root = undefined;
        SOCKETAPIURL = undefined;
        heartBeatInterval = undefined;
        RELOAD = false;
        currentReload = 0;
        RELOADTOTAL = 0;
        reloadTimeout = undefined;
        reloadDelay = 1000;
        DELAY = 0;
        error = Object.create(null);
        _state = -1;
        get state() {
            return this._state;
        }
        set state(val) {
            this._state = val;
            console.log("[state]", this.root.readyState)
            switch (val) {
                case 0:
                    break;
                case 1:
                    this.currentReload = 0;
                    this.beforeConnect();
                    this.createHearBeat();
                    break;
                case 2:
                    break;
                case 3:
                    if (this.RELOAD) {
                        this.auxReload(true);
                        return;
                    }
                    this.destroy();
                    break;
                default:
                    break;
            }
        }
        auxReload() {
            const that = this;
            if (this.currentReload < this.RELOADTOTAL) {
                this.reloadTimeout && clearTimeout(this.reloadTimeout);
                this.reloadTimeout = setTimeout(() => {
                    that.currentReload += 1;
                    that.createSocket().catch(err => console.error(err)).then(() => {
                        that.afterReload();
                        that.createHearBeat();
                    });
                }, this.reloadDelay)
            }
        }
        createReload() {
            this.createSocket().catch(err => console.error(err))
            return this;
        }
        beforeConnect() {
            if (this.options.beforeHearBeat) {
                const json = this.options.beforeHearBeat.call(this, this.error)
                json && this.root && this.root.send(json)
            }
        }
        afterReload() {
            if (this.options.afterReload) {
                const json = this.options.afterReload.call(this, this.error)
                json && this.root && this.root.send(json)
            }
        }
        createHearBeat() {
            if (this.root && this.root.readyState === 1 && this.options.singleHearBeat) {
                this.root.send(this.options.singleHearBeat.call(this, this.error))
                this.heartBeatInterval && clearInterval(this.heartBeatInterval)
                this.heartBeatInterval = setInterval(() => {
                    this.root.send(this.options.singleHearBeat.call(this, this.error))
                }, this.DELAY);
            }
            return this;
        }
        destroy() {
            this.heartBeatInterval && clearInterval(this.heartBeatInterval)
            this.root && this.root.close()
            return this;
        }
        createSocket() {
            const that = this;
            const skMessage = (event) => {
                console.log("[socket message]", event)
                if (that.options.messageReceived) {
                    const json = that.options.messageReceived(event.data)
                    if (json) {
                        event = document.createEvent("HTMLEvents");
                        event.initEvent("skMessage", false, true);
                        event.detail = json;
                        global.dispatchEvent(event);
                    }
                }
            }
            if (typeof this.SOCKETAPIURL === 'string' && /^w+/.test(this.SOCKETAPIURL)) {
                return new Promise((resolve, reject) => {
                    try {
                        that.destroy();
                        that.root = new WebSocket(that.SOCKETAPIURL);
                        that.root.onopen = () => {
                            that.state = that.root.readyState
                        }
                        that.root.onmessage = skMessage

                        that.root.onerror = (event) => {
                            console.error("[socket error]", event)
                            that.error = event
                            that.state = 3
                        }
                        that.root.onclose = (e) => {
                            console.log(e)
                            that.state = that.root.readyState
                        }
                        resolve()
                    } catch (err) {
                        reject(err)
                    }
                })
            }
            return Promise.resolve();
        }
    }

    return {
        createSocket(ops) {
            const socketControl = new SocketControl(ops)
            return socketControl;
        }
    }
})